package com.bluebench.bigul.utility.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

import com.bluebench.bigul.domain.Tag;
import com.bluebench.bigul.domain.Types;

public class ReflectionUtil {
	
	public static void invokeMethod(String methodName, Tag object,Class[] typeArray,Object[] valueArray) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		
		Class<?> clazz = object.getClass();
		Method method = clazz.getMethod(methodName, typeArray);
		method.invoke(object, valueArray);
	}
	
	public static String getSetter(String fieldName){
		char c = fieldName.charAt(0);
		fieldName = "set"+fieldName.replaceFirst(String.valueOf(c), String.valueOf(Character.toUpperCase(c)));
		return fieldName;
	}
	
	public static Object getFieldValueFromElement(String field){		
		Object returnVal=null;
		System.out.println("FIELD : "+field);
		if(field.contains(".")){
			String[] parts = field.split("\\.");
			String className = Types.getType(parts[0]).getClassName();
			String fieldName = parts[1];
			try {
				
				Class<?> clazz = Class.forName(className);
				System.out.println("CLASSNAME : "+className);
				Field f = clazz.getField(fieldName);				
				if(!clazz.isInterface()){
					//Object instance = clazz.newInstance();
					returnVal = f.get(null);
				}else{
					returnVal = f.get(null);
				}				
				
			} catch (IllegalAccessException e1) {					
				e1.printStackTrace();
			} catch (ClassNotFoundException e1) {					
				e1.printStackTrace();
			} catch (SecurityException e1) {					
				e1.printStackTrace();
			} catch (NoSuchFieldException e1) {					
				e1.printStackTrace();
			} 
		}
		
		return returnVal;
	}
	
	public static Method find(Class<?> clazz,String methodName, Class<?>[] paramArray){
		
		Method method=null;		
		boolean flag=false;
		try {
			
			method = clazz.getDeclaredMethod(methodName, paramArray);
		} catch (NoSuchMethodException e) {
			
			do{
				 Method[] methods = clazz.getDeclaredMethods();
				 next:
				  for(Method m : methods){
					if(m.getName().equals(methodName)){
						Class<?>[] paramTypes = m.getParameterTypes();
						if(paramTypes.length==paramArray.length){
							//Ensure parameters are either same or assignable
							if(paramTypes.length==0){
								flag=true;
							}
							for(int i=0;i<paramTypes.length;i++){
								if(paramArray[i].equals(paramTypes[i])||paramTypes[i].isAssignableFrom(paramArray[i])){
									flag=true;									
								}else{
									flag=false;
									continue next;
								}
							}
							
							if(flag){
								return m;
							}					
							
						}				
					}
					
				  }
				  
				  clazz=clazz.getSuperclass();
				}while(clazz.getSuperclass()!=null);
			
			return method;	
		}
		return method;
	}
	
	public static Object instantiate(Class<?> className,Class<?>[] constructorArgClassTypes,Object[] constructorArgValues) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, SecurityException,  ClassNotFoundException{
		Object instance = null;
		try{
			Constructor<?> constructor = className.getConstructor(constructorArgClassTypes);				
			instance = constructor.newInstance(constructorArgValues);
		
		}catch(NoSuchMethodException e){
			
			Constructor<?>[] ctors = className.getConstructors();
			boolean flag=false;
			for(Constructor<?> c : ctors){
				Class<?>[] types = c.getParameterTypes();
				if(types.length == constructorArgClassTypes.length){
					for(int i=0;i<types.length;i++){
						if(types[i].isAssignableFrom(constructorArgClassTypes[i])){
							flag=true;
							constructorArgValues[i] = types[i].cast(constructorArgValues[i]);
						}else{
							flag=false;
						}
					}
					if(flag){
						instance = c.newInstance(constructorArgValues);
					}
				}
			}		
		}
		
		return instance;
	}
	
	public static void main(String[] args) {
		
	}

}
